
#include "mainWindow.h"
#include "imageLoader.h"
#include "CNetworkManager.h"

#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>

#include <QtGui/QImage>

/*----------------------------------------------------------------------------*/

MainWindow::MainWindow()
	:	m_ui( new Ui::MainWindowUi )
	,	m_sourceImage( NULL )
	,	m_detectedImages()
{
	m_networkManager = new CNetworkManager();
	m_imageLoader = new ImageLoader();	
	m_newNetworkWizard = new NewNetworkWizard( *m_networkManager );
	m_trainNetworkWizard = new TrainNetworkWizard( *m_imageLoader, *m_networkManager );	
	m_optionsWindow = new OptionsWindow();

	m_ui->setupUi( this );	

	/** Action: Open */
	connect( m_ui->m_actionOpen, SIGNAL( triggered() ), this, SLOT( OpenImage() ) );

	/**  Action: Close */
	connect( m_ui->m_actionClose, SIGNAL( triggered() ), this, SLOT( CloseImage() ) );

	/** Action: New network */
	connect( m_ui->m_actionNewNetwork, SIGNAL( triggered() ), this, SLOT( NewNetwork() ) );

	/** Action: Save network */
	connect( m_ui->m_actionSaveNetwork, SIGNAL( triggered() ), this, SLOT( SaveNetwork() ) );

	/** Action: Save As network */
	connect( m_ui->m_actionSaveAsNetwork, SIGNAL( triggered() ), this, SLOT( SaveNetworkAs() ) );

	/** Action: Load network */
	connect( m_ui->m_actionLoadNetwork, SIGNAL( triggered() ), this, SLOT( LoadNetwork() ) );

	/** Action: Close network */
	connect( m_ui->m_actionCloseNetwork, SIGNAL( triggered() ), this, SLOT( CloseNetwork() ) );

	/** Action: Train network */
	connect( m_ui->m_actionTrainNetwork, SIGNAL( triggered() ), this, SLOT( TrainNetwork() ) );

	/** Action: Options */
	connect( m_ui->m_actionOptions, SIGNAL( triggered() ), this, SLOT( OpenOptions() ) );

	/** Action: About */
	connect( m_ui->m_actionAbout, SIGNAL( triggered() ), this, SLOT( About() ) );

	/** Action: Quit */
	connect( m_ui->m_actionQuit, SIGNAL( triggered() ), this, SLOT( close() ) );

	/** Network enabled */
	connect( m_newNetworkWizard, SIGNAL( NetworkAccessible( bool ) ), this, SLOT( NetworkIsAccessible( bool ) ) );

	/** Image enabled */
	connect( m_ui->m_displayWidget, SIGNAL( ImageAccessible( bool ) ), this, SLOT( ImageIsAccessible( bool ) ) );

	/** Button: Classify image */
	connect( m_ui->m_runClassification, SIGNAL( clicked() ), this, SLOT( RunClassification() ) );

	/** Action: Find images */	
	connect( m_ui->m_actionDetectImages, SIGNAL( triggered() ), this, SLOT( SegmentateImage() ) );
	
	/** Action: Save images */
	connect( m_ui->m_actionSaveImages, SIGNAL( triggered() ), this, SLOT( SaveImagesOnDisk() ) );

	/** Options changed signal */
	connect( m_optionsWindow, SIGNAL( FramesShowState( bool, bool, bool ) ),
		m_ui->m_displayWidget, SLOT( SetFramesShowing( bool, bool, bool ) ) );	

	/** other stuff */
	m_optionsWindow->EmitFramesShowState();
	this->show();
}


/*----------------------------------------------------------------------------*/


MainWindow::~MainWindow()
{
	if( m_optionsWindow )
		delete m_optionsWindow;
	if( m_trainNetworkWizard )
		delete m_trainNetworkWizard;
	if( m_newNetworkWizard )
		delete m_newNetworkWizard;
	if( m_imageLoader )
		delete m_imageLoader;
	if ( m_networkManager )
		delete m_networkManager;
	if( m_sourceImage )
		delete m_sourceImage;
	if( m_ui )
		delete m_ui;
}


/*----------------------------------------------------------------------------*/


void MainWindow::TrainNetwork()
{
	if( !m_networkManager->NetworkExists() )
	{
		WarningNetworkNotExists();
		return;
	}

	m_trainNetworkWizard->ShowCentered( *this );
}


/*----------------------------------------------------------------------------*/


void MainWindow::About()
{
	QMessageBox::about( this, "About", "Designed by:\n - Stanislav Kudriashev" );
}


/*----------------------------------------------------------------------------*/


void MainWindow::NewNetwork()
{
	if ( m_networkManager->NetworkExists() && !WarningOverwriteNetwork() )			
		return;	

	m_newNetworkWizard->ShowCentered( *this );	
}


/*----------------------------------------------------------------------------*/


void MainWindow::SaveNetwork()
{
	QString fileName;
	if ( m_networkManager->GetNetworkFileName().empty() )
	{
		fileName = GetSaveFileNameDialog();

		if ( !fileName.size() )
			return;		

		QApplication::setOverrideCursor( Qt::WaitCursor );
		m_networkManager->SaveNetwork( fileName.toAscii().data() );
		QApplication::setOverrideCursor( Qt::ArrowCursor );
	}
	else
	{
		QApplication::setOverrideCursor( Qt::WaitCursor );
		m_networkManager->SaveNetwork( m_networkManager->GetNetworkFileName() );
		QApplication::setOverrideCursor( Qt::ArrowCursor );
	}
}


/*----------------------------------------------------------------------------*/


void MainWindow::LoadNetwork()
{
	if( m_networkManager->NetworkExists() && !WarningOverwriteNetwork() )			
		return;

	QString fileName = QFileDialog::getOpenFileName(
			this
		,	tr( "Open" )
		,	QDir::current().absolutePath()
		,	tr( "Network (*.neuro);;Any files (*.*)" )		
	);

	if( !fileName.size() )
		return;
	
	QApplication::setOverrideCursor( Qt::WaitCursor );	
	m_networkManager->LoadNetwork( fileName.toAscii().data() );
	QApplication::setOverrideCursor( Qt::ArrowCursor );

	emit NetworkIsAccessible( true );
}


/*----------------------------------------------------------------------------*/


bool MainWindow::WarningOverwriteNetwork()
{
	int result = QMessageBox::warning( 
		this
		,	"Warning"
		,	"A network is already opened, do you want to overwrite it?"
		,	QMessageBox::Yes
		,	QMessageBox::No
		);
	
	return result == QMessageBox::Yes;
}


/*----------------------------------------------------------------------------*/


void MainWindow::CloseNetwork()
{
	m_networkManager->CloseNetwork();

	emit NetworkIsAccessible( false );
}


/*----------------------------------------------------------------------------*/


void MainWindow::NetworkIsAccessible( bool _state )
{
	m_ui->m_actionSaveNetwork->setEnabled( _state );
	m_ui->m_actionSaveAsNetwork->setEnabled( _state );
	m_ui->m_actionTrainNetwork->setEnabled( _state );
	m_ui->m_actionCloseNetwork->setEnabled( _state );
	if ( m_sourceImage )
		m_ui->m_runClassification->setEnabled( _state );
}


/*----------------------------------------------------------------------------*/


void MainWindow::SaveNetworkAs()
{
	QString fileName = GetSaveFileNameDialog();

	if ( !fileName.size() )
		return;
	
	QApplication::setOverrideCursor( Qt::WaitCursor );
	m_networkManager->SaveNetwork( fileName.toAscii().data() );
	QApplication::setOverrideCursor( Qt::ArrowCursor );

	m_ui->m_actionSaveNetwork->setEnabled( false );
}


/*----------------------------------------------------------------------------*/


QString MainWindow::GetSaveFileNameDialog()
{
	return QFileDialog::getSaveFileName(
		this
		,	tr( "Save" )
		,	QDir::current().absolutePath()
		,	tr( "Network (*.neuro)" )
	);
}


/*----------------------------------------------------------------------------*/


void MainWindow::OpenImage()
{
	QString imageName = QFileDialog::getOpenFileName(
		this
		,	tr( "Open" )
		,	QDir::current().absolutePath()
		,	tr( "Image (*.bmp);;Any files (*.*)" )		
		);

	if( !imageName.size() )
		return;	
	
	if( m_sourceImage )
		delete m_sourceImage;
	m_sourceImage = new QImage( imageName );
	m_ui->m_console->clear();
	m_ui->m_displayWidget->SetImage( *m_sourceImage );
}


/*----------------------------------------------------------------------------*/


void MainWindow::CloseImage()
{
	if ( m_sourceImage )
		delete m_sourceImage;
	m_sourceImage = NULL;
	m_ui->m_console->clear();
	m_ui->m_displayWidget->CloseImage();
}


/*----------------------------------------------------------------------------*/


void MainWindow::RunClassification()
{
	if ( !m_networkManager->NetworkExists() )
	{
		WarningNetworkNotExists();
		return;
	}

	/** segmentation */
	QApplication::setOverrideCursor( Qt::WaitCursor );
	SegmentateImage();
	QApplication::setOverrideCursor( Qt::ArrowCursor );
	if ( m_detectedImages.size() == 0 )
	{
		QMessageBox::warning( this, "Warning", "No symbols were detected on the image!" );
		return;
	}

	/** prepare result console */	
	m_ui->m_console->clear();
	m_ui->m_console->insertPlainText( QString( "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" ) );

	/** set wait cursor */
	QApplication::setOverrideCursor( Qt::WaitCursor );
	
	/** classification */
	int currSymbol = 0;
	for ( size_t i = 0; i < m_symbolsLayout.size(); i++ )
	{
		for ( size_t j = 0; j < m_symbolsLayout[i].size(); j++ )
		{
			int wordSize = m_symbolsLayout[i][j];
			for ( int s = currSymbol; s < currSymbol + wordSize; s++ )
			{
				CImage* img = m_imageLoader->CreateImageFromBmp( m_detectedImages[s] );
				QChar imageClass = m_networkManager->ClassifyImage( *img );
				if ( img )				
					delete img;
				m_ui->m_console->insertPlainText( QString( imageClass ) );				
			}
			currSymbol += wordSize;
			m_ui->m_console->insertPlainText( QString( " " ) );
		}
		m_ui->m_console->insertPlainText( QString( "\n" ) );
	}

	/** end of wait cursor */
	QApplication::setOverrideCursor( Qt::ArrowCursor );
}


/*----------------------------------------------------------------------------*/


void MainWindow::ImageIsAccessible( bool _state )
{	
	m_ui->m_actionClose->setEnabled( _state );
	m_ui->m_actionDetectImages->setEnabled( _state );
	m_ui->m_actionSaveImages->setEnabled( _state );
	if ( m_networkManager->NetworkExists() )
		m_ui->m_runClassification->setEnabled( _state );
}


/*----------------------------------------------------------------------------*/


void MainWindow::WarningNetworkNotExists()
{
	QMessageBox::warning( this, "Warning", "Network is not accessible!\n\nCreate new network or\nload existing one." );
}


/*----------------------------------------------------------------------------*/


void MainWindow::SegmentateImage()
{	
	/** getting options */
	int imageSize = m_optionsWindow->GetImageSizeValue();
	int imageContrast = m_optionsWindow->GetImageContrastValue();
	float lineExpandFactor = m_optionsWindow->GetLineExpandFactor();
	float lineTopFactor = m_optionsWindow->GetLineTopFactor();
	float lineBotFactor = m_optionsWindow->GetLineBotFactor();
	float wordLeftFactor = m_optionsWindow->GetWordLeftFactor();
	float wordRightFactor = m_optionsWindow->GetWordRightFactor();
	float symbIntervalFactor = m_optionsWindow->GetSymbIntervalFactor();
	float symbBrightFactor = m_optionsWindow->GetSymbBrightFactor();
	float symbWidthFactor = m_optionsWindow->GetSymbWidthFactor();

	/** segmentator */
	ImageSegmentator segmentator(	*m_sourceImage
								,	imageSize
								,	imageContrast
								,	lineExpandFactor
								,	lineTopFactor
								,	lineBotFactor
								,	wordLeftFactor
								,	wordRightFactor
								,	symbIntervalFactor
								,	symbBrightFactor
								,	symbWidthFactor
								);

	/** getting segmentation results */
	m_ui->m_displayWidget->SetLinesFrames( segmentator.GetLinesFrames() );
	m_ui->m_displayWidget->SetWordFrames( segmentator.GetWordsFrames() );
	m_ui->m_displayWidget->SetSymbolFrames( segmentator.GetSymbolsFrames() );	
	m_detectedImages = segmentator.GetSymbolsImages();
	m_symbolsLayout = segmentator.GetSymbolsLayout();
}


/*----------------------------------------------------------------------------*/


void MainWindow::OpenOptions()
{	
	m_optionsWindow->ShowCentered( *this );
}


/*----------------------------------------------------------------------------*/


void MainWindow::SaveImagesOnDisk()
{	
	for ( size_t i = 0; i < m_detectedImages.size(); i++ )
	{
		QString name;
		name.setNum( i );		
		m_detectedImages[i].save( "./DetectedImages/symbol_" + name + ".bmp", "BMP" );		
	}	
}


/*----------------------------------------------------------------------------*/

